/*
    Copyright 2006 Andrew Wilkinson <andrew@indiegigs.co.uk>

    This file is part of libgp2x.

    libgp2x is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    libgp2x is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with libgp2x; if not, write to the Free Software
    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
*/

#include <linux/fb.h>
#include <sys/mman.h>
#include <sys/time.h>
#include <stdio.h>
#include <string.h>

#include "gp2x_internal.h"

unsigned short* GP2x_screens[2];
unsigned long GP2x_screen_addr[2];

unsigned char GP2x_940_control_screen;

void GP2x_video_init() {
    GP2x_screens[0] = (unsigned short*)(0x01101000 + GP2x_upper_memory);
    GP2x_screens[1] = (unsigned short*)(0x01381000 + GP2x_upper_memory);

    GP2x_screen_addr[0] = 0x03101000;
    GP2x_screen_addr[1] = 0x03381000;

    /* Bits 1, 3, 5, 7 are fixed to 1. Bit 0 is set 1 to enable region 1. Bits 9-10 are set to 2 to make it 16bpp. */
    GP2x_register(GP2x_REG_BIT_DEPTH) = (unsigned short)0x04ab;  /* hex(1|1<<1|1<<3|1<<5|1<<7|2<<9) */
    GP2x_register(GP2x_REG_LINE_WIDTH) = (unsigned short)0x0280; /* Line width in bytes*/

    /* Set the current screen to screen 0. */
    GP2x_screen = GP2x_screens[0];

    GP2x_940_control_screen = 0;

    /* Clear the screen. */
    memset(GP2x_screen, 0, 320*240*2); GP2x_flip_unsync();
    memset(GP2x_screen, 0, 320*240*2); GP2x_flip_unsync();
}

void GP2x_flip() {
    if(GP2x_940_control_screen) {
        GP2x_postMessage(GP2x_MESSAGE_FLIP_SYNC, 0, 0);
        return;
    }

    GP2x_video_vsync();
    GP2x_flip_unsync();
}

void GP2x_flip_unsync() {
static struct timeval starttime;
static int framecount = 0;
    struct timeval now;

    if(GP2x_940_control_screen) {
        GP2x_postMessage(GP2x_MESSAGE_FLIP_UNSYNC, 0, 0);
        return;
    }

    if(GP2x_screen == GP2x_screens[0]) {
        GP2x_screen = GP2x_screens[1];
        GP2x_register(0x290E) = GP2x_register(0x2912) = GP2x_screen_addr[0] & 0xFFFF;
        GP2x_register(0x2910) = GP2x_register(0x2914) = GP2x_screen_addr[0] >> 16;
    } else {
        GP2x_screen = GP2x_screens[0];
        GP2x_register(0x290E) = GP2x_register(0x2912) = GP2x_screen_addr[1] & 0xFFFF;
        GP2x_register(0x2910) = GP2x_register(0x2914) = GP2x_screen_addr[1] >> 16;
    }

    while(~GP2x_register(GP2x_REG_SCREEN_SYNC) & (1 << 4));

    if(framecount == 0) {
        gettimeofday(&starttime, 0);
    }
    framecount++;
    gettimeofday(&now, 0);
    if(now.tv_sec - starttime.tv_sec >= 5) {
        printf("Average frame rate %ffps.\n", framecount/5.0);
        framecount = 0;
    }

}

void GP2x_video_hsync() {
    while(GP2x_register(GP2x_REG_SCREEN_SYNC) & (1 << 5));
}

void GP2x_video_vsync() {
    while(GP2x_register(GP2x_REG_SCREEN_SYNC) & (1 << 4));
}
